const next = Promise.resolve()
const emptyFn = args => args
function Aop(obj, method, { before = emptyFn, after = emptyFn }) {
  const srcMethod = obj[method]

  obj[method] = function () {
    next.then(() => {
      return before.apply(null, arguments)
    }).then(args => {
      return srcMethod.call(obj, args)
    }).then(() => {
      return after.apply(null, arguments)
    })
  }
}

class Car {
  constructor(name) {
    this.name = name
  }
  run() {
    return Promise.resolve().then(() => {
      console.log(this.name + ' is running.')
    })
  }
  adp(setter) {
    return prop => {
      console.log(setter[prop])
    }
  }
}

const car = new Car('JEEP')


Aop(car, 'adp', {
  before(args) {
    console.log('run.before', args)
    return args;
  },
  after(args) {
    console.log('run.after')
    return args;
  }
})



car.adp({ a: 123, b: 456 })//('a')
// car.run(456)
// car.run(789)